#pragma once
#include <string>
#include "../Util/Singleton.h"
#include "../Objects/Object.h"
#include "../Objects/Door.h"
#include "../Objects/Player.h"
#include "../Objects/Enemy.h"
#include "../Rules/LevelRules.h"
#include <tinystr.h>
#include <tinyxml.h>
#include <vector>
#include <list>
#ifdef _WIN32
#include <windows.h>
#endif

//Enumerator for every type content
enum eSpecialCellContent 
{
  eObject = 0,
  eDoor,
  ePlayer,
  eSpecialLocation,
  eEnemy
};

//Define Special Cell structure
struct cSpecialCell
{
  char mcId;
  int miX;
  int miY;
  eSpecialCellContent meCellContent;
  std::string mName;
};

//Singleton class that load the level into memory from an XML
class cLevel: public cSingleton<cLevel>
{
  friend class cSingleton<cLevel>;
protected:
  cLevel() {;}
private:
  //Typedef to simplify the sintax
  typedef std::list<cSpecialCell> cSpecialCellDictionary;
  typedef cSpecialCellDictionary::iterator cSpecialCellDictionaryIt;
  typedef std::vector<cObject *> cObjectList;
  typedef cObjectList::iterator cObjectListIt;

  //Attributes
  int miLevelWidth; //Level width
  int miLevelHeight; //Level height
  bool *mWalls; //Array to hold the walls of the level
  cSpecialCellDictionary mDictionary; //Collection of special cells
  cObjectList mObjects; //Collection of objects
  cLevelRules mRules;  //Collection of rulesf
  cObject *moPlayer;  //A reference to the player
  int miLevelList; //Display List
  bool mbFreeze; //Freeze update level
  std::string msFilename; //Name of the file 
  //Private Methods
  void LoadMap(TiXmlElement *lpMap);
  void LoadCells(TiXmlElement *lpCells);
  void LoadRules(TiXmlElement *lpRules);
  bool IsWallCharacter(char lcChar);
public:
  void Init(const std::string lsFilename);
  void Load(std::string lsFilename);
  void Update(float lfTimeStep);
  void Render();
  void Deinit();
  bool IsWall(unsigned int luiX, unsigned int luiY);
  bool IsInCell(char lcCellId, std::string lsObjectName); 
  bool IsInPlayerCell(std::string lsObjectName);
  bool IsInPlayerCellKind(std::string lsType);
  void InsertObject(cObject *lcObject);
  void RemoveObject(std::string lsObjectName);
  inline cObject *GetPlayer() {return moPlayer;}
  std::vector<cObject *> GetEnemies();
  void MoveObject(std::string lsObjectName, char lcCellId);
  void QuitLevel();
  void Freeze();
  void Unfreeze();
  void GetObject(std::string lsObjectName);
  void Restart();
};
